#ifndef LIBCO_CHANNEL_H
#define LIBCO_CHANNEL_H

#include <cstdint>
#include <queue>
#include "mutex.hpp"

namespace libco {

template <typename T>
class Channel {
public:
    explicit Channel(size_t buffer_size = 0) : m_buffer_size(buffer_size) {}

    // 发送数据
    void send(const T& value) {
        Mutex::Lock lock(m_mtx);
        LIBCO_ASSERT2(!m_closed, "Channel is closed, cannot send data.");
        if (m_buffer_size == 0) {
            // 无缓冲模式
            // 等待接收者准备好
            m_waiting_recv = true;
            m_data = value;
            m_cv_send.wait(lock, [this] { return m_waiting_send; });
            m_waiting_send = false;
            m_cv_receive.notify_all(); // 通知接收者
        } else {
            // 带缓冲模式
            m_cv_send.wait(lock, [this] { return m_queue.size() < m_buffer_size; });
            m_queue.push(value);
            m_cv_receive.notify_all();
        }
    }

    // 接收数据
    T receive() {
        Mutex::Lock lock(m_mtx);
        LIBCO_ASSERT2(!(m_closed && m_queue.empty() && !m_waiting_recv), "Channel is closed and empty, cannot receive data.");
        if (m_buffer_size == 0) {
            // 无缓冲模式
            // 等待发送者发送数据
            m_waiting_send = true;
            m_cv_receive.wait(lock, [this] { return m_waiting_recv; });
            m_waiting_recv = false;
            T value = m_data;
            m_cv_send.notify_all(); // 通知发送者
            return value;
        } else {
            // 带缓冲模式
            m_cv_receive.wait(lock, [this] { return !m_queue.empty(); });
            T value = m_queue.front();
            m_queue.pop();
            m_cv_send.notify_all();
            return value;
        }
    }

    // 关闭通道
    void close() {
        Mutex::Lock lock(m_mtx);
        m_closed = true;
        m_cv_send.notify_all();
        m_cv_receive.notify_all();
    }

    // 检查通道是否关闭
    bool is_closed() const {
        return m_closed;
    }

    // 重载操作符，模拟 Go 语言的 <- 操作符（发送）
    Channel& operator<<(T value) {
        send(value);
        return *this;
    }

    // 重载操作符，模拟 Go 语言的 -> 操作符（接收）
    T operator>>(T& value) {
        value = receive();
        return value;
    }

private:
    /// @brief 无缓冲模式下的数据
    T m_data;
    bool m_waiting_send = false;
    bool m_waiting_recv = false;

    /// @brief 带缓冲模式下的数据
    std::queue<T> m_queue;
    size_t m_buffer_size;

    /// @brief 互斥锁和条件变量

    Mutex m_mtx;
    ConditionVariable m_cv_send;
    ConditionVariable m_cv_receive;
    bool m_closed = false;
};


} // namespace libco

#endif //LIBCO_CHANNEL_H